#include <iostream>
#include <string.h>
using std::cout;
using std::endl;
using std::ostream;
class cowString{
public:
    cowString();
    cowString(const char * pstr);
    cowString(const cowString & rhs);
    cowString & operator=(const cowString & rhs);
    int refcount();
    int size();
private:
    class charProxy{
    public:
        charProxy(cowString & cows,int index);
        friend ostream & operator<<(ostream & os,const cowString::charProxy & charP);
        char & operator=(char ch);
    private:
        cowString & _cows;
        int _index;
    };
public:
    charProxy operator[](int index);
    friend ostream & operator<<(ostream & os,const cowString::charProxy & charP);
private:
    char * _pstr;
};

cowString::charProxy::charProxy(cowString & cows,int index)
:_cows(cows)
,_index(index)
{}

cowString::charProxy cowString::operator[](int index){
    return charProxy(*this,index);
}

ostream & operator<<(ostream & os,const cowString::charProxy & charP){
    if(charP._index >= charP._cows.size()){
        char nullchar = '\0';
        os << nullchar;
    }else{
        os << charP._cows._pstr[charP._index];
    }
    return os;
}
char & cowString::charProxy::operator=(char ch){
    if(_index >= _cows.size()){
        static char nullchar = '\0';
        return nullchar;
    }
    if(ch != _cows._pstr[_index]){
        if(_cows.refcount() > 1){
            --*(int*)(_cows._pstr - 4);
            char * temp = new char[_cows.size() + 4 + 1]() +4;
            strcpy(temp,_cows._pstr);
            _cows._pstr = temp;
        }
        _cows._pstr[_index] = ch;
    }
    return _cows._pstr[_index];
}

void test(){
    cowString s1("hello");
    cowString s2("world");
    cowString s3(s1);
    cout << s3.refcount() << endl;
    s3 = s2;
    cout << s1.refcount() << endl;
    cout << s3.refcount() << endl;
}

void test2(){
    cowString s("hello");
    cowString s2(s);
    cout << s2.refcount() << endl;
    cout << s[0] << endl;
    s[0] = 'H';
    cout << s[0] << endl;
    cout << s2.refcount() << endl;
}

int main()
{
    test2 ();
    return 0;
}

cowString::cowString()
:_pstr(new char[1+4]() + 4)
{
}
cowString::cowString(const char * pstr)
:_pstr(new char[strlen(pstr) + 1 + 4]() +4)
{
    *(int*)(_pstr-4) = 1;
    strcpy(_pstr,pstr);
}
cowString::cowString(const cowString & rhs)
:_pstr(rhs._pstr)
{
    *(int *)(_pstr -4) += 1;
}

cowString & cowString::operator=(const cowString & rhs){
    if(this != &rhs){
        if(--*(int*)(_pstr-4) == 0){
            delete [] _pstr;
        }
        _pstr = rhs._pstr;
        ++*(int*)(_pstr -4);
    }
    return *this;
}
int cowString::refcount(){
    return *(int*)(_pstr -4);
}
int cowString::size(){
    return strlen(_pstr);
}
